"""
CLI interface for LogRun Manager.
"""

import click
import sys
from pathlib import Path
from typing import List, Optional

from .runner import CommandRunner
from .storage import LogStorage
from .models import LogEntry

ZERO_DURATION_THRESHOLD = 0.05


def format_duration(seconds: Optional[float]) -> str:
    """Format duration in human-readable format."""
    if seconds is None:
        return "N/A"
    
    if seconds < 60:
        return f"{seconds:.1f}s"
    elif seconds < 3600:
        minutes = seconds / 60
        return f"{minutes:.1f}m"
    else:
        hours = seconds / 3600
        return f"{hours:.1f}h"


def format_log_entry(entry: LogEntry, show_details: bool = False) -> str:
    """Format a log entry for display."""
    status_symbols = {
        "success": "✅",
        "failed": "❌",
        "running": "🟡"
    }
    
    symbol = status_symbols.get(entry.status, "❓")
    duration_str = format_duration(entry.duration)
    
    if show_details:
        lines = [
            f"{symbol} #{entry.id}: {entry.command}",
            f"    Started: {entry.start_time.strftime('%Y-%m-%d %H:%M:%S') if entry.start_time else 'N/A'}",
            f"    Status: {entry.status.upper()}",
            f"    Duration: {duration_str}",
            f"    Log file: {entry.log_file}"
        ]
        if entry.tags:
            lines.append(f"    Tags: {', '.join(entry.tags)}")
        return "\n".join(lines)
    else:
        time_str = entry.start_time.strftime('%m-%d %H:%M') if entry.start_time else 'N/A'
        return f"{symbol} #{entry.id:3d} | {time_str} | {duration_str:>6} | {entry.command[:60]}"


def preprocess_show_log_args():
    """Preprocess arguments to handle --show-log without an ID."""
    import sys
    args = sys.argv[1:]
    
    # Check if --show-log is present without an argument
    for i, arg in enumerate(args):
        if arg in ['--show-log', '-s']:
            # Check if next arg exists and is not another option
            if i + 1 >= len(args) or args[i + 1].startswith('-'):
                # Insert empty string as argument for --show-log
                args.insert(i + 1, '')
                sys.argv[1:] = args
                break
    
    return args

@click.command(context_settings=dict(ignore_unknown_options=True, allow_extra_args=True))
@click.option('--help', '-h', 'help_flag', is_flag=True, help='Show this message and exit')
@click.option('--list', '-l', 'list_logs', is_flag=True, help='List recent log entries')
@click.option('--show-log', '-s', type=str, metavar='ID[,ID...]', default=None, help='Show log content for specific ID(s), supports comma-separated values. Defaults to latest log if no ID provided.')
@click.option('--delete', '--rm', '-d', 'delete_id', type=int, metavar='LOG-ID', help='Delete a runlog by ID and refresh sequence numbers')
@click.option('--cleanup', is_flag=True, help='Clean up old log files')
@click.option('--stats', is_flag=True, help='Show statistics')
@click.option('--tag', multiple=True, help='Add tags to the command execution')
@click.pass_context
def cli(ctx, help_flag, list_logs, show_log, delete_id, cleanup, stats, tag):
    """
    LogRun - Command execution with automatic logging and history management.
    
    Usage examples:
        logrun gsm test-remote --solver=gcr --gpu=hip --debug
        logrun -h              # Show help
        logrun --list
        logrun --show-log 5
        logrun --show-log 3,4,5
        logrun --show-log    # Shows latest log
        logrun -d 5          # Delete log entry #5 and refresh sequence
        logrun --delete 5    # Same as -d 5
        logrun --cleanup
    """
    storage = LogStorage()
    
    # Handle help flag explicitly
    if help_flag:
        click.echo(ctx.get_help())
        return
    
    # Handle management commands
    if delete_id is not None:
        remove_log_command(storage, delete_id)
        return
    
    if list_logs:
        # Use first tag as filter if multiple tags are provided
        tag_filter = tag[0] if tag else None
        list_command(storage, tag_filter=tag_filter)
        return
    
    if show_log is not None:
        # Use first tag as filter if multiple tags are provided
        tag_filter = tag[0] if tag else None
        show_log_command(storage, show_log, tag_filter)
        return
    
    if cleanup:
        cleanup_command(storage)
        return
    
    if stats:
        stats_command(storage)
        return
    
    # Debug output (disabled)
    # print(f"DEBUG: ctx.args = {ctx.args}")
    # print(f"DEBUG: sys.argv = {sys.argv}")
    
    # If we have extra arguments, treat them as a command to execute
    if ctx.args:
        command = ctx.args
        runner = CommandRunner()
        exit_code, entry = runner.run_command(command, list(tag) if tag else None)
        sys.exit(exit_code)
    
    # No command provided, show help
    click.echo(ctx.get_help())


def list_command(storage: LogStorage, limit: int = 20, tag_filter: str = None):
    """List recent log entries."""
    entries = storage.get_entries(limit=limit, tag_filter=tag_filter)
    
    if not entries:
        if tag_filter:
            click.echo(f"No log entries found with tag '{tag_filter}'.")
        else:
            click.echo("No log entries found.")
        return
    
    if tag_filter:
        click.echo(f"Recent log entries with tag '{tag_filter}' ({len(entries)} shown):")
    else:
        click.echo(f"Recent log entries ({len(entries)} shown):")
    
    # Check if any entries have tags to determine if we should show tags column
    has_tags = any(entry.tags for entry in entries)
    
    if has_tags:
        click.echo("ID  | Date/Time  | Duration | Tags       | Command")
        click.echo("-" * 95)
    else:
        click.echo("ID  | Date/Time  | Duration | Command")
        click.echo("-" * 80)
    
    for entry in entries:
        if has_tags:
            tags_str = ', '.join(entry.tags[:2]) if entry.tags else ''  # Show first 2 tags
            if len(entry.tags) > 2:
                tags_str += '...'
            # Format with tags
            symbol = {"success": "✅", "failed": "❌", "running": "🟡"}.get(entry.status, "❓")
            duration_str = format_duration(entry.duration)
            time_str = entry.start_time.strftime('%m-%d %H:%M') if entry.start_time else 'N/A'
            click.echo(f"{symbol} #{entry.id:3d} | {time_str} | {duration_str:>6} | {tags_str:10} | {entry.command[:50]}")
        else:
            click.echo(format_log_entry(entry))


def show_log_command(storage: LogStorage, entry_ids: str, tag_filter: str = None):
    """Show log content for specific entry(ies)."""
    
    # Handle case where no ID is provided (default to latest)
    if not entry_ids or entry_ids.strip() == '':
        entries = storage.get_entries(limit=1, tag_filter=tag_filter)
        if entries:
            entry_ids = str(entries[0].id)
            if tag_filter:
                click.echo(f"No ID provided, using latest log ID with tag '{tag_filter}': {entry_ids}")
            else:
                click.echo(f"No ID provided, using latest log ID: {entry_ids}")
        else:
            if tag_filter:
                click.echo(f"❌ No logs found with tag '{tag_filter}' to show")
            else:
                click.echo("❌ No logs found to show")
            return
    
    # Parse comma-separated IDs
    try:
        id_list = [int(id_str.strip()) for id_str in entry_ids.split(',')]
    except ValueError:
        click.echo(f"❌ Invalid ID format: '{entry_ids}'. Use numeric IDs separated by commas.")
        return
    
    for i, entry_id in enumerate(id_list):
        if i > 0:
            click.echo("\n" + "=" * 80 + "\n")
        
        entry = storage.get_entry(entry_id)
        
        if not entry:
            click.echo(f"❌ Log entry #{entry_id} not found.")
            continue
        
        click.echo(format_log_entry(entry, show_details=True))
        click.echo()
        
        log_path = Path(entry.log_file)
        if log_path.exists():
            click.echo("Log content:")
            click.echo("-" * 40)
            with open(log_path, 'r') as f:
                click.echo(f.read())
        else:
            click.echo(f"❌ Log file not found: {entry.log_file}")


def cleanup_command(storage: LogStorage, days: int = 30):
    """Clean up old log files."""
    click.echo(f"🧹 Cleaning up log entries older than {days} days...")
    
    before_count = len(storage.get_entries())
    storage.cleanup_old_entries(days)
    after_count = len(storage.get_entries())
    
    removed_count = before_count - after_count
    click.echo(f"✅ Removed {removed_count} old log entries.")

    # Remove zero-duration entries
    zero_duration_entries = [
        entry for entry in storage.get_entries(limit=None)
        if entry.duration is not None and entry.duration < ZERO_DURATION_THRESHOLD
    ]

    if zero_duration_entries:
        click.echo(f"🧽 Removing {len(zero_duration_entries)} near-zero log entries (<{ZERO_DURATION_THRESHOLD:.2f}s)...")
        removed_zero = 0
        for entry in zero_duration_entries:
            if storage.delete_entry(entry.id):
                removed_zero += 1
        if removed_zero:
            storage.resequence_ids()
        click.echo(f"✅ Removed {removed_zero} near-zero log entries.")
    else:
        click.echo("ℹ️  No zero-duration log entries found.")


def stats_command(storage: LogStorage):
    """Show statistics about log entries."""
    stats = storage.get_statistics()
    
    click.echo("📊 LogRun Statistics:")
    click.echo(f"Total entries: {stats['total_entries']}")
    click.echo(f"Successful: {stats['successful']} ✅")
    click.echo(f"Failed: {stats['failed']} ❌")
    click.echo(f"Running: {stats['running']} 🟡")
    click.echo()
    
    if stats['command_frequency']:
        click.echo("Top commands:")
        for cmd, count in stats['command_frequency'].items():
            click.echo(f"  {cmd}: {count}")


def remove_log_command(storage: LogStorage, log_id: int):
    """Remove a specific log entry and resequence IDs."""
    # Check if the entry exists
    entry = storage.get_entry(log_id)
    if not entry:
        click.echo(f"❌ Log entry #{log_id} not found.")
        return
    
    # Show what will be deleted
    click.echo(f"🗑️ Deleting log entry:")
    click.echo(format_log_entry(entry, show_details=True))
    
    # Delete the entry
    success = storage.delete_entry(log_id)
    if not success:
        click.echo(f"❌ Failed to delete log entry #{log_id}.")
        return
    
    # Resequence IDs
    click.echo("🔢 Refreshing sequence numbers...")
    storage.resequence_ids()
    
    click.echo(f"✅ Successfully deleted log entry #{log_id} and refreshed sequence numbers.")


def main():
    """Main entry point for CLI."""
    # Preprocess arguments to handle --show-log without ID
    preprocess_show_log_args()
    
    # Run the CLI
    cli()

if __name__ == '__main__':
    main()
